package dt.inlee.common.interceptor;

import java.io.PrintWriter;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.TextParseUtil;

import dt.inlee.common.constant.CommonConstant;
import dt.inlee.common.exception.FrameworkException;
import dt.inlee.common.util.BaseUtil;
import dt.inlee.common.util.SystemResourceUtil;
import dt.inlee.diancan.action.DiancanAction;
import dt.inlee.system.action.LoginSSoAction;
import dt.inlee.system.vo.SysUserLoginBean;

/**
 * 
 * @功能：权限认证拦截器
 * @作者：印鲜刚
 * @创建日期：2010-04-20
 * 
 */
public class PrivilegeInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = 6790323148524586610L;
    @SuppressWarnings("unused")
    private static Logger log = Logger.getLogger(PrivilegeInterceptor.class);
    // 不进行拦截的方法
    protected Set<String> excludeMethods = Collections.emptySet();

    public void setExcludeMethods(String excludeMethods) {
        this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
    }

    public Set<String> getExcludeMethodsSet() {
        return excludeMethods;
    }

    /**
     * 权限认证接口
     */
    @SuppressWarnings({"unchecked", "unused"})
    @Override
    public String intercept(ActionInvocation invocation) throws FrameworkException, Exception {
        String result = null;
        // 1.获取要调用的方法
        // 2.获取该方法的权限
        // 3.认证权限
        // 4.有权限正常执行，没权限返回指定路径
        ActionSupport actionSupport = (ActionSupport) invocation.getAction();
        ActionProxy actionProxy = invocation.getProxy();
        String methodName = actionProxy.getMethod();

        String referer = ServletActionContext.getRequest().getHeader("Referer");
        // Action是否为SSO登陆
        if (LoginSSoAction.class == invocation.getAction().getClass()) {
            return invocation.invoke();
        }
        // method方法如果是testlogin说明是物业增值平台直接调用登录
        /*if (methodName.equals("testlogin") || methodName.equals("wsSaveGeographyInfo")) {
            return invocation.invoke();
        }*/
        
        //点餐系统。。不处理
        if(actionSupport.getClass().equals(DiancanAction.class)){
            return invocation.invoke();
        }
        
        if(ActionContext.getContext().getSession().get("diancanren") != null){
            
        }

        // 防盗链,用户直接在浏览器地址里面输入action
        if (referer == null) {
            return Action.LOGIN;
        }

        if (!isExcludeMethod(methodName)) {
            // 判断用户是否登录
            Map<String, Object> session = invocation.getInvocationContext().getSession();
            Object obj = session.get(CommonConstant.SESSION_USER);
            String accept = ServletActionContext.getRequest().getHeader("Accept");
            if (obj == null) {
                if (!accept.startsWith("application/json")) {
                    return Action.LOGIN;
                }
                // 当客服端请求其他类型的时候(json),设置响应头，并设置响应状态为401(未授权)
                String path = ServletActionContext.getServletContext().getContextPath();
                HttpServletResponse response = ServletActionContext.getResponse();
                response.setStatus(401);
                response.addHeader("Error-Json", "{reason:'notLogin',content:'" + path + "'}");
                return null;

            } else {
                System.out.println("==="+SystemResourceUtil.getInstance().getResourceAsString("LOGIN_POLICY")+"---");
                String policy = SystemResourceUtil.getInstance().getResourceAsString("LOGIN_POLICY").trim();
                if (BaseUtil.isEmpty(policy) || policy.equalsIgnoreCase("kick_repeat")) {
                    // 取得界面输入的用户名
                    String userName =
                            ((SysUserLoginBean) ServletActionContext.getRequest().getSession()
                                    .getAttribute(CommonConstant.SESSION_USER)).getUserName();
                    // 在线用户列表
                    Map<String, String> onlineUser = Collections.emptyMap();
                    ServletContext sc = ServletActionContext.getServletContext();
                    onlineUser = (Map<String, String>) sc.getAttribute(CommonConstant.SERVLETCONTEXT_ONLINE_USER);
                    // 取得当前登录的SessionId
                    String currSession = ServletActionContext.getRequest().getSession().getId();

                    // 如果取得用户列表为空，直接执行其他的拦截器
                    if (onlineUser == null) {
                        return invocation.invoke();
                    }
                    String oldSession = onlineUser.get(userName);
                    // 如果当前登录用户未存入在线用户列表(未登录),执行其他拦截器
                    if (oldSession == null) {
                        return invocation.invoke();
                    }
                    // 当登录账号的新旧session不一致时 表示为重复登录
                    if (!oldSession.equals(currSession)) {
                        // 当客服端请求为text/html的时候直接返回登录界面
                        if (!accept.startsWith("application/json")) {
                            String reLoginMessage =
                                    "<script type='text/javascript'>" + "alert('对不起该账号已经在其他地方登录,你已被踢出1111!');"
                                            + "window.top.location.href='" + sc.getContextPath()
                                            + "/page/exitLogin.action';" + "</script>";
                            ServletActionContext.getResponse().setHeader("content-type", "text/html; charset=utf-8");
                            PrintWriter out = ServletActionContext.getResponse().getWriter();
                            // 页面上显示
                            out.println(reLoginMessage);
                            out.flush();
                            out.close();
                            return null;
                        }
                        // 当客服端请求其他类型的时候(json),设置响应头，并设置响应状态为401(未授权)
                        String path = ServletActionContext.getServletContext().getContextPath();
                        HttpServletResponse response = ServletActionContext.getResponse();
                        response.setStatus(402);
                        response.addHeader("Error-Json", "{reason:'kickRepeatLogin',content:'" + path + "'}");
                        return null;
                    }
                }
            }
        }
        try {
            result = invocation.invoke();
        } catch (FrameworkException e) {
            e.printStackTrace();
            FrameworkException frameworkException = new FrameworkException(e);
            frameworkException.log();
            return handleException();
        } catch (Exception e) {
            e.printStackTrace();
            FrameworkException frameworkException = new FrameworkException(e);
            frameworkException.log();
            return handleException();
        }
        return result;
    }

    /**
     * 异常类型分类处理
     */
    private String handleException() {
        String accept = ServletActionContext.getRequest().getHeader("Accept");
        // 当客服端请求为text/html的时候直接返回登录界面
        if (!accept.startsWith("application/json")) {
            return "exception";
        }
        // 当客服端请求其他类型的时候(json),设置响应头，并设置响应状态为401(未授权)
        String path = ServletActionContext.getServletContext().getContextPath();
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setStatus(500);
        response.addHeader("Error-Json", "{reason:'insideError',content:'" + path + "'}");
        return null;
    }

    /**
     * 判断是否为不需要登录验证的方法
     */
    private boolean isExcludeMethod(String methodName) {
        for (String method : excludeMethods) {
            if (method.equals(methodName)) {
                return true;
            }
        }
        return false;
    }
}
